package com.cci.kangdao.utilTool;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPatch;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

/**
 * @author William Du
 * @date 2019/4/8
 */
public class HttpUtils {

        public static final String DEFAULT_ENCODING = "utf8";
        public static final String JSON_CONTENT_TYPE = "application/json;chatset=utf8";
        public static final String XML_CONTENT_TYPE = "application/xml";
        public static final int TIME_OUT = 60000;
        private  static Logger log = Logger.getLogger(HttpUtils.class);

        public static <T> T postForm(String url, List<NameValuePair> parameter,
                                     ResponseHandler<T> handler) {
            return postForm(url, parameter, handler, (Header[]) null);
        }

        public static <T> T postForm(String url, List<NameValuePair> parameter,
                                     ResponseHandler<T> handler, Header... header) {
            T res = null;

            org.apache.http.client.HttpClient client = createClient(url);

            HttpPost post = new HttpPost(url);
            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(TIME_OUT).setConnectionRequestTimeout(TIME_OUT).setSocketTimeout(TIME_OUT).build();
            post.setConfig(requestConfig);
            try {
                if (header != null) {
                    for (Header each : header) {
                        post.setHeader(each);
                    }
                }
                if(null != parameter){
                    post.setEntity(new UrlEncodedFormEntity(parameter, StandardCharsets.UTF_8));
                }

                res = client.execute(post, handler);
            } catch (Exception e) {
                throw new IllegalStateException(e);
            } finally {
                post.releaseConnection();
            }
            return res;
        }


        public static <T> T postJson(String url, ResponseHandler<T> handler) {
            return postJson(url, null, handler, (Header[]) null);
        }

        public static <T> T postJson(String url, String jsonString,
                                     ResponseHandler<T> handler) {
            return postJson(url, jsonString, handler, (Header[]) null);
        }

        public static <T> T postJson(String url, ResponseHandler<T> handler,
                                     Header... header) {
            return postJson(url, null, handler, header);
        }

        public static <T> T postJsonBean(String url, Object param, final Class<T> resultClazz,
                                         Header... header) {
            String jsonString = JsonUtils.toJsonString(param);
            ResponseHandler<T> handler = new ResponseHandler<T>() {
                public T handleResponse(HttpResponse response)
                        throws ClientProtocolException, IOException {
                    if (response.getStatusLine().getStatusCode() == 200) {
                        // http请求正常返回
                        HttpEntity httpEntity = response.getEntity();
                        T obj = JsonUtils.toJavaObject(
                                EntityUtils.toString(httpEntity), resultClazz);
                        return obj;
                    } else {
                        throw new IllegalStateException("post json bean fail:" + response.getStatusLine().getStatusCode());
                    }
                }
            };

            return postJson(url, jsonString, handler, header);
        }

        public static <T> T postJson(String url, String jsonString,
                                     ResponseHandler<T> handler, Header... header) {
            T res = null;

            HttpClient client = createClient(url);

            HttpPost post = new HttpPost(url);
            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(TIME_OUT).setConnectionRequestTimeout(TIME_OUT).setSocketTimeout(TIME_OUT).build();
            post.setConfig(requestConfig);
            // 设置重试次数
            int maxRetries = 3;
            int currentRetry = 0;
            while (currentRetry <= maxRetries) {
                try {
                    if (header != null) {
                        for (Header each : header) {
                            post.setHeader(each);
                        }
                    }

                    if (StringUtils.isNotEmpty(jsonString)) {
                        StringEntity s = new StringEntity(jsonString, DEFAULT_ENCODING);
                        s.setContentType(JSON_CONTENT_TYPE);
                        post.setEntity(s);
                    }

                    res = client.execute(post, handler);
                    break; // 成功后退出循环
                } catch (Exception e) {
                    log.error("post json fail, retry times:" + currentRetry, e);
                    if (currentRetry == maxRetries) {
                        throw new IllegalStateException(e);
                    }
                    // 增加重试次数
                    currentRetry++;
                } finally {
                    post.releaseConnection();
                }
            }
            return res;
        }

    public static <T> T patchJson(String url, String jsonString,
                                 ResponseHandler<T> handler, Header... header) {
        T res = null;

        org.apache.http.client.HttpClient client = createClient(url);

        HttpPatch patch = new HttpPatch(url);
        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(TIME_OUT).setConnectionRequestTimeout(TIME_OUT).setSocketTimeout(TIME_OUT).build();
        patch.setConfig(requestConfig);
        try {
            if (header != null) {
                for (Header each : header) {
                    patch.setHeader(each);
                }
            }

            if (StringUtils.isNotEmpty(jsonString)) {
                StringEntity s = new StringEntity(jsonString, DEFAULT_ENCODING);
                s.setContentType(JSON_CONTENT_TYPE);
                patch.setEntity(s);
            }

            res = client.execute(patch, handler);
        } catch (Exception e) {
            throw new IllegalStateException(e);
        } finally {
            patch.releaseConnection();
        }
        return res;
    }

        public static <T> T get(String url, ResponseHandler<T> handler,
                                Header... header) {
            T res = null;

            org.apache.http.client.HttpClient client = createClient(url);

            HttpGet get = new HttpGet(url);
            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(TIME_OUT).setConnectionRequestTimeout(TIME_OUT).setSocketTimeout(TIME_OUT).build();
            get.setConfig(requestConfig);
            try {
                if (header != null) {
                    for (Header each : header) {
                        get.setHeader(each);
                    }
                }

                res = client.execute(get, handler);
            } catch (Exception e) {
                throw new IllegalStateException(e);
            } finally {
                get.releaseConnection();
            }
            return res;
        }

        public static <T> T get(String url, Map<String, String> parameter, ResponseHandler<T> handler,
                                Header... header) {
            StringBuffer sb = new StringBuffer(url).append("?");
            parameter.forEach((k, v) -> sb.append(k).append("=").append(v).append("&"));
            String getUrl = sb.substring(0, sb.length() - 1);
            return get(getUrl, handler, header);
        }

        public static <T> T putJson(String url, String jsonString,
                                    ResponseHandler<T> handler, Header... header) {
            T res = null;

            org.apache.http.client.HttpClient client = createClient(url);

            HttpPut put = new HttpPut(url);
            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(TIME_OUT).setConnectionRequestTimeout(TIME_OUT).setSocketTimeout(TIME_OUT).build();
            put.setConfig(requestConfig);
            try {
                if (header != null) {
                    for (Header each : header) {
                        put.setHeader(each);
                    }
                }

                if (StringUtils.isNotEmpty(jsonString)) {
                    StringEntity s = new StringEntity(jsonString, DEFAULT_ENCODING);
                    s.setContentType(JSON_CONTENT_TYPE);
                    put.setEntity(s);
                }

                res = client.execute(put, handler);
            } catch (Exception e) {
                throw new IllegalStateException(e);
            } finally {
                put.releaseConnection();
            }
            return res;
        }

        public static <T> T postXml(String url, String xmlString, String encoding,
                                    ResponseHandler<T> handler) {
            return postXml(url, xmlString, encoding, handler, (Header[]) null);
        }

        public static <T> T postXml(String url, String xmlString, ResponseHandler<T> handler) {
            return postXml(url, xmlString, DEFAULT_ENCODING, handler, (Header[]) null);
        }

        public static <T> T postXml(String url, String xmlString, String encoding,
                                    ResponseHandler<T> handler, Header... header) {
            T res = null;

            org.apache.http.client.HttpClient client = createClient(url);

            HttpPost post = new HttpPost(url);
            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(TIME_OUT).setConnectionRequestTimeout(TIME_OUT).setSocketTimeout(TIME_OUT).build();
            post.setConfig(requestConfig);
            try {
                if (header != null) {
                    for (Header each : header) {
                        post.setHeader(each);
                    }
                }

                if (StringUtils.isNotEmpty(xmlString)) {
                    StringEntity s = new StringEntity(xmlString, encoding);
                    s.setContentType(XML_CONTENT_TYPE);
                    post.setEntity(s);
                }

                res = client.execute(post, handler);
            } catch (Exception e) {
                throw new IllegalStateException(e);
            } finally {
                post.releaseConnection();
            }
            return res;
        }

        private static org.apache.http.client.HttpClient createClient(String url) {
            org.apache.http.client.HttpClient client = null;
            if (url.startsWith("https")) {
                client = createSSLClientDefault();
            } else if (url.startsWith("http")) {
                client = HttpClients.createDefault();
            }
            return client;
        }

        private static HttpClient createSSLClientDefault() {
            try {
                SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(
                        null, new TrustStrategy() {
                            // 信任所有
                            @Override
                            public boolean isTrusted(X509Certificate[] chain,
                                                     String authType) throws CertificateException {
                                return true;
                            }
                        }).build();
                SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                        sslContext);
                return HttpClients.custom().setSSLSocketFactory(sslsf).build();
            } catch (Exception e) {
                throw new IllegalStateException(e);
            }
        }

    public static String createUrlWithParameters(String url, Map<String, String> parameters) {
        StringBuffer sb = (new StringBuffer(url)).append("?");
        parameters.forEach((k, v) -> {
            if (StringUtils.isNotBlank(k) && StringUtils.isNotEmpty(v)) {
                sb.append(k).append("=").append(v).append("&");
            }
        });
        return sb.substring(0, sb.length() - 1);
    }

    public static String createUrlWithSortedParameters(String url, Map<String, String> parameters) {
        StringBuilder resultBuffer = new StringBuilder().append(url).append("?").append(createSortedParameters(parameters));
        return resultBuffer.toString();
    }

    public static String createSortedParameters(Map<String, String> parameters) {
        List<Map.Entry<String, String>> paramList = new ArrayList<>(parameters.entrySet());
        CollectionUtils.sort(paramList, Comparator.comparing(o -> (o.getKey())));
        StringBuilder buf = new StringBuilder();
        for (Map.Entry<String, String> item : paramList) {
            if (StringUtils.isNotBlank(item.getKey()) && StringUtils.isNotEmpty(item.getValue())) {
                buf.append(item.getKey()).append("=").append(item.getValue()).append("&");
            }
        }
        StringBuilder resultBuffer = new StringBuilder().append(buf.toString());
        return resultBuffer.deleteCharAt(resultBuffer.length() - 1).toString();
    }

        public static void main(String[] args) {
            String a = "http://api.fist.xinxiannv.com/metadata/getRegion.do";
            postJson(
                    a,// "http://www.xinxiannv.com:9080/fist/metadata/getRegion.do",
                    "{\"channel\":2, \"protocolVer\":\"1.0\", \"appVer\":\"1.0\"}",
                    new ResponseHandler<String>() {

                        @Override
                        public String handleResponse(HttpResponse response)
                                throws ClientProtocolException, IOException {

                            if (response.getStatusLine().getStatusCode() == 200) {
                                HttpEntity httpEntity = response.getEntity();
                                System.out.println(EntityUtils.toString(httpEntity));

                            }
                            System.out.println(response.getStatusLine()
                                    .getStatusCode());
                            return null;
                        }
                    });
        }
}
